/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "napi/native_api.h"
#include <string>
#include "napi_util.h"

napi_status NapiUtil::GetDouble(napi_env env, napi_value arg, double *value) {
  napi_valuetype value_type = napi_undefined;
  CHECK_NAPI_STATUS(napi_typeof(env, arg, &value_type), "Failed to get type");
  CHECK_COND(value_type == napi_number, napi_number_expected, "Type is not as expected number");
  CHECK_NAPI_STATUS(napi_get_value_double(env, arg, value), "Failed to get double type");
  return napi_ok;
}
napi_status NapiUtil::GetFloat(napi_env env, napi_value arg, float *value) {
  napi_valuetype value_type = napi_undefined;
  CHECK_NAPI_STATUS(napi_typeof(env, arg, &value_type), "Failed to get type");
  CHECK_COND(value_type == napi_number, napi_number_expected, "Type is not as expected number");
  double double_value;
  CHECK_NAPI_STATUS(napi_get_value_double(env, arg, &double_value), "Failed to get double type");
  *value = static_cast<float>(double_value);
  return napi_ok;
}
napi_status NapiUtil::GetInt32(napi_env env, napi_value arg, int32_t *value) {
  napi_valuetype value_type = napi_undefined;
  CHECK_NAPI_STATUS(napi_typeof(env, arg, &value_type), "Failed to get type");
  CHECK_COND(value_type == napi_number, napi_number_expected, "Type is not as expected number");
  CHECK_NAPI_STATUS(napi_get_value_int32(env, arg, value), "Failed to get int32 type");
  return napi_ok;
}
napi_status NapiUtil::GetInt64(napi_env env, napi_value arg, int64_t *value) {
  napi_valuetype value_type = napi_undefined;
  CHECK_NAPI_STATUS(napi_typeof(env, arg, &value_type), "Failed to get type");
  CHECK_COND(value_type == napi_bigint || value_type == napi_number, napi_bigint_expected,
             "Type is not as expected number/bigint");
  if (value_type == napi_bigint) {
    bool success;
    CHECK_NAPI_STATUS(napi_get_value_bigint_int64(env, arg, value, &success), "Failed to get bigint type");
    CHECK_COND(success, napi_ok, "get bigint fail"); //如果精度丢失，打印错误信息，但是任然认为正常解析
  } else {
    CHECK_NAPI_STATUS(napi_get_value_int64(env, arg, value), "Failed to get int64 value");
  }
  return napi_ok;
}
napi_status NapiUtil::GetUInt32(napi_env env, napi_value arg, uint32_t *value) {
  napi_valuetype value_type = napi_undefined;
  CHECK_NAPI_STATUS(napi_typeof(env, arg, &value_type), "Failed to get type");
  CHECK_COND(value_type == napi_number, napi_number_expected, "Type is not as expected number");
  CHECK_NAPI_STATUS(napi_get_value_uint32(env, arg, value), "Failed to get uint32 type");
  return napi_ok;
}
napi_status NapiUtil::GetUInt64(napi_env env, napi_value arg, uint64_t *value) {
  napi_valuetype value_type = napi_undefined;
  CHECK_NAPI_STATUS(napi_typeof(env, arg, &value_type), "Failed to get type");
  CHECK_COND(value_type == napi_number | value_type == napi_bigint, napi_bigint_expected,
             "Type is not as expected number");
  if (value_type == napi_number) {
    int64_t temp_int64;
    CHECK_NAPI_STATUS(napi_get_value_int64(env, arg, &temp_int64), "Failed to get int64 value");
    *value = temp_int64;
    return napi_ok;
  }
  bool success;
  CHECK_NAPI_STATUS(napi_get_value_bigint_uint64(env, arg, value, &success), "Failed to get uint64 type");
  CHECK_COND(success, napi_bigint_expected, "Failed to get uint64 type");
  return napi_ok;
}

napi_status NapiUtil::GetBool(napi_env env, napi_value arg, bool *value) {
  napi_valuetype value_type = napi_undefined;
  CHECK_NAPI_STATUS(napi_typeof(env, arg, &value_type), "Failed to get type");
  CHECK_COND(value_type == napi_boolean, napi_boolean_expected, "Type is not as expected bool");
  CHECK_NAPI_STATUS(napi_get_value_bool(env, arg, value), "Failed to get bool type");
  return napi_ok;
}
napi_status NapiUtil::GetStringUtf8(napi_env env, napi_value arg, std::string *value) {
  napi_valuetype value_type = napi_undefined;
  CHECK_NAPI_STATUS(napi_typeof(env, arg, &value_type), "Failed to get type");
  CHECK_COND(value_type == napi_string, napi_string_expected, "Type is not as expected string");
  size_t result_length;
  CHECK_NAPI_STATUS(napi_get_value_string_utf8(env, arg, nullptr, 0, &result_length), "Failed to get string type");
  value->resize(result_length);
  CHECK_NAPI_STATUS(napi_get_value_string_utf8(env, arg, &(*value)[0], result_length + 1, nullptr),
                    "Failed to get string type");
  return napi_ok;
}

napi_status NapiUtil::GetUint8Array(napi_env env, napi_value arg, size_t *length, void **data, napi_value *arraybuffer,
                                    size_t *byte_offset) {
  napi_valuetype value_type = napi_undefined;
  CHECK_NAPI_STATUS(napi_typeof(env, arg, &value_type), "Failed to get type");
  bool isTypeArray = false;
  CHECK_NAPI_STATUS(napi_is_typedarray(env, arg, &isTypeArray), "napi value is not a type array");

  napi_typedarray_type array_type;
  napi_value buffer;
  CHECK_NAPI_STATUS(napi_get_typedarray_info(env, arg, &array_type, length, data, &buffer, byte_offset),
                    "napi get typedarray error");
  CHECK_COND(array_type == napi_uint8_array, napi_string_expected, "type is not uint8array type");
  return napi_ok;
}
bool NapiUtil::CheckObject(napi_env env, napi_value arg) {
  napi_valuetype value_type = napi_undefined;
  CHECK_COND(napi_typeof(env, arg, &value_type) == napi_ok, false, "Failed to get type");
  CHECK_COND(value_type == napi_object, false, "Type is not as expected object");
  return true;
}
